#include "ps2game.h"

#include "gameobjectcollection.h"
#include "model.h"
#include "skybox.h"

#include "pad.h"

PS2Game::PS2Game() : Game() {
    this->asteroidController = NULL;
    this->directionalLight = NULL;
    this->fireDelay = 0.0f;
    this->hud = NULL;
	this->light = NULL;
    this->player = NULL;
    this->projectiles = new vector<Projectile*>();
}

PS2Game::~PS2Game(void) {
    delete this->directionalLight;
	delete this->light;
	
    for (vector<Projectile*>::const_iterator it = this->projectiles->begin(); it != this->projectiles->end(); ++it) {
        delete *it;
    }

    this->projectiles->clear();
    delete this->projectiles;
}

void PS2Game::Initialize() {
    Skybox* skybox = new Skybox(this);
    this->GetGameObjects()->Add(skybox);

    this->asteroidController = new AsteroidController(this);
    this->GetGameObjects()->Add(this->asteroidController);
	
	this->light = new Projectile(this);
	this->light->SetPosition(Vector4(0.0f, 2.0f, 2.0f, 0.0f));
	this->GetGameObjects()->Add(this->light);

    this->player = new Ship(this);
    this->GetGameObjects()->Add(this->player);

    this->hud = new Hud(this);
    this->GetGameObjects()->Add(hud);

    this->directionalLight = new Light();
    this->directionalLight->color = Vector4(1.0f, 1.0f, 1.0f, 1.0f);
    this->directionalLight->direction = Vector4(1.0f, 1.0f, 1.0f, 0.0f).Normalise();
    this->directionalLight->type = LIGHTTYPE_DIRECTIONAL;
    this->GetLightManager()->Add(this->directionalLight);
    this->GetLightManager()->SetAmbientLight(Vector4(0.05f, 0.05, 0.05, 0.0f));

    Pipeline.SetNearPlane(0.1f);
    Pipeline.SetFarPlane(10000.0f);
    Pipeline.SetVisibleRadius(4096.0f);

    Game::Initialize();
    this->light->GetLight()->attenuation0 = 1.0f;
    this->light->GetLight()->attenuation1 = 0.0f;
}

void PS2Game::Draw(float timeDelta) {
    Game::Draw(timeDelta);
}

void PS2Game::LoadContent() {
    Game::LoadContent();
}

void PS2Game::UnloadContent() {
    Game::UnloadContent();
}

void PS2Game::Update(float timeDelta) {
    pad_update(PAD_0);

    static bool prevSquare = pad[0].pressed & PAD_SQUARE;
    if (pad[0].pressed & PAD_SQUARE && !prevSquare) {
        bool enableOctree = this->asteroidController->GetEnableOctree();
        this->asteroidController->SetEnableOctree(!enableOctree);
    }

    if ((pad[0].buttons & PAD_START) && (pad[0].buttons & PAD_SELECT)) {
        this->Stop();
    }

    this->player->SetActionAdvance(-pad[0].axes[PAD_AXIS_LY]);
    this->player->SetActionRotateX(pad[0].axes[PAD_AXIS_RY]);
    this->player->SetActionRotateY(-pad[0].axes[PAD_AXIS_LX]);
    this->player->SetActionRotateZ(pad[0].axes[PAD_AXIS_RX]);

	Light* pLight = this->light->GetLight();
	pLight->attenuation1 += (pad[0].pressures[PAD_PL1] / 50) - (pad[0].pressures[PAD_PR1] /  50);

	if (pLight->attenuation1 < 0) {
		pLight->attenuation1 = 0;
	}

	if (pLight->attenuation1 > 1) {
		pLight->attenuation1 = 1;
	}

    vector<Projectile*>::iterator it = this->projectiles->begin();
    while (it != this->projectiles->end()) {
        Projectile* projectile = *it;
        if (projectile->GetLife() <= 0) {
            it = this->projectiles->erase(it);
            this->GetGameObjects()->Remove(projectile);
            delete projectile;
        } else {
            ++it;
        }
    }

    this->hud->SetNumberOfAsteroidsDrawn(this->asteroidController->GetNumberOfAsteroidsDrawn());

    Game::Update(timeDelta);

    if (this->fireDelay > 0.0f) {
        this->fireDelay -= timeDelta;
    } else if (pad[0].pressed & PAD_CROSS) {
        Projectile* projectile = new Projectile(this);
        projectile->SetPosition(this->player->GetPosition());
        projectile->SetDirection(this->player->GetDirection());
        projectile->Initialize();
        projectile->LoadContent();
        this->projectiles->push_back(projectile);
        this->fireDelay = 0.5f;
        this->GetGameObjects()->Add(projectile);
    }

    Vector4 lookAt = Vector4(Pipeline.GetCameraX(), Pipeline.GetCameraY(), Pipeline.GetCameraZ(), 0) + this->player->GetDirection() * 100;
    Vector4 up = this->player->GetUpVector();
    Vector4 camPos = this->player->GetPosition() - this->player->GetDirection() * 10 + up * 3;
    Pipeline.PositionCamera(camPos, lookAt, up);
}
